package com.ruoyi.common.utils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Node;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;


/**
 * @ClassName:  ElasticSearchUtils
 * @Description: ElasticSearch助手类具体实类
 * @author: chenyang
 * @date:   2019年4月20日 下午5:09:49
 *
 */
public class ElasticSearchUtils {
	
    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchUtils.class);
	
	private static String[] cluster_serverips = null;// elasticSearch服务器ip
	// 创建私有对象
	private static RestHighLevelClient client;
	
	public static void init(String address) {
		try {

			// 读取信息
			cluster_serverips = address.split(",");

			Node[] nodes = new Node[cluster_serverips.length];
	        for(int i=0; i<cluster_serverips.length; i++) {
	        	String cluster_serverip[] = cluster_serverips[i].split(":");
				String host = cluster_serverip[0];
				String portStr = cluster_serverip.length>1? (StringUtils.isBlank(cluster_serverip[1])?"9200":cluster_serverip[1]) :"9200";
				HttpHost httpHost = new HttpHost(host, Integer.parseInt(portStr), "http");
				nodes[i] = new Node(httpHost);
			}
			client = new RestHighLevelClient(RestClient.builder(nodes));
			LOGGER.info("加载ES配置成功！");
		} catch (Exception e) {
			e.printStackTrace();
			LOGGER.error("加载ES配置出错！\r\n"+e.getMessage());
		}
	}
	
	public static RestHighLevelClient getClient() {
		return client;
	}

	/**
	 * json格式内容添加
	 * @param index
	 * @param docId
	 * @param jsonStr
	 * @return
	 */
	public static boolean addJsonDoc(String index, String docId, String jsonStr) {
		boolean result = false;

		RestHighLevelClient client = getClient();

		IndexRequest request = new IndexRequest(index); 
		if(StringUtils.isNoneBlank(docId)) {
			request.id(docId); 
		}
		request.source(jsonStr, XContentType.JSON);
		
		try {
			IndexResponse response = client.index(request, RequestOptions.DEFAULT);
			
			//结果信息
			index = response.getIndex();
			String id = response.getId();
			String gettype = response.getType();
			long version = response.getVersion();
			RestStatus status = response.getShardInfo().status();


			if (status.getStatus() == RestStatus.CREATED.getStatus()) {
				String strResult = "新增文档成功 " + index + ": " + gettype + ": " + id + ": " + version + ": " + status.getStatus();
				LOGGER.info(strResult);
				result = true;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 关闭client
		return result;
	}
	
	public static BulkResponse bulkAdd(String indexName, List<?> bulks, String idPropertyName) {
	    try{
	        BulkRequest bulkRequest = new BulkRequest();
	        //超时时间设长点，30分钟
	        bulkRequest.timeout(TimeValue.timeValueMinutes(30L));
	        for(Object bulk: bulks) {
	        	IndexRequest request = new IndexRequest(indexName); 
	        	
	    		if(StringUtils.isNotBlank(idPropertyName)) {
	    			String id = BeanUtilsBean.getInstance().getProperty(bulk, idPropertyName);
	    			if(id!=null) {
	    				request.id(id); 
	    			}
	    		}
	    		request.source(JsonBeanUtil.transBean2Json(bulk), XContentType.JSON);
	    		
	            bulkRequest.add(request);
	        }
	        BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
	        return response;
	    }catch (Exception e){
	    	LOGGER.error("同步失败：{}", e.getMessage());
	    }
	    return null;
	}
	
	public static BulkResponse bulkAdd(BulkRequest bulkRequest) {
	    try{
	        BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
	        return response;
	    }catch (Exception e){
	    	LOGGER.error("同步失败：{}", e.getMessage());
	    }
	    return null;
	}
	
	/**
	 * 异步方法执行
	 * @param index
	 * @param docId
	 * @param jsonStr
	 */
	public static void addJsonDocAsync(String index, String docId, String jsonStr) {
		RestHighLevelClient client = getClient();

		IndexRequest request = new IndexRequest(index); 
		if(StringUtils.isNoneBlank(docId)) {
			request.id(docId); 
		}
		request.source(jsonStr, XContentType.JSON);
		
		try {
			ActionListener<IndexResponse> listener = new ActionListener<IndexResponse>() {
			    @Override
			    public void onResponse(IndexResponse response) {
			    	String index = response.getIndex();
					String id = response.getId();
					String gettype = response.getType();
					long version = response.getVersion();
					RestStatus status = response.getShardInfo().status();


					if (status.getStatus() == RestStatus.CREATED.getStatus()) {
						String strResult = "新增文档成功 " + index + ": " + gettype + ": " + id + ": " + version + ": " + status.getStatus();
						LOGGER.info(strResult);
					}
			    }

				@Override
				public void onFailure(Exception e) {
					// TODO Auto-generated method stub
					
				}
			};
			
			client.indexAsync(request, RequestOptions.DEFAULT, listener);
		} catch (Exception e) {
			e.printStackTrace();
		}
		}
	
	/**
	 * 实体类添加
	 * @param index
	 * @param docId
	 * @param entity
	 * @return
	 */
	public static boolean addEntityDoc(String index, String docId, Object entity) {
		boolean result = false;

		RestHighLevelClient client = getClient();

		IndexRequest request = new IndexRequest(index); 
		if(StringUtils.isNoneBlank(docId)) {
			request.id(docId); 
		}
		request.source(JsonBeanUtil.transBean2Json(entity), XContentType.JSON);
		
		try {
			IndexResponse response = client.index(request, RequestOptions.DEFAULT);
			
			//结果信息
			index = response.getIndex();
			String id = response.getId();
			String gettype = response.getType();
			long version = response.getVersion();
			RestStatus status = response.getShardInfo().status();


			if (status.getStatus() == RestStatus.CREATED.getStatus()) {
				String strResult = "新增文档成功 " + index + ": " + gettype + ": " + id + ": " + version + ": " + status.getStatus();
				LOGGER.info(strResult);
				result = true;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 关闭client
		return result;
	}
	

	/**
	 * Map方式添加
	 * @param index
	 * @param docId
	 * @param mapParam
	 * @return
	 */
	public static boolean addMapDoc(String index, String docId, Map<String, Object> mapParam) {
		boolean result = false;

		RestHighLevelClient client = getClient();

		IndexRequest request = new IndexRequest(index); 
		if(StringUtils.isNoneBlank(docId)) {
			request.id(docId); 
		}
		request.source(mapParam);
		
		try {
			IndexResponse response = client.index(request, RequestOptions.DEFAULT);
			
			//结果信息
			index = response.getIndex();
			String id = response.getId();
			String gettype = response.getType();
			long version = response.getVersion();
			RestStatus status = response.getShardInfo().status();


			if (status.getStatus() == RestStatus.CREATED.getStatus()) {
				String strResult = "新增文档成功 " + index + ": " + gettype + ": " + id + ": " + version + ": " + status.getStatus();
				LOGGER.info(strResult);
				result = true;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 关闭client
		return result;
	}
	
	/**
	 * 返回json数据
	 * @param index
	 * @param docId
	 * @return
	 */
	public static String getDocAsJson(String index, String docId) {
		String result = null;

		RestHighLevelClient client = getClient();

		GetRequest getRequest = new GetRequest(index).id(docId);
		
		try {
			GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
			
			if (getResponse.isExists()) {
				result = getResponse.getSourceAsString();
			} 
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	/**
	 * 返回实体类型数据
	 * @param <T>
	 * @param index
	 * @param docId
	 * @param clazz
	 * @return
	 */
	public static <T> T getDocAsEntity(String index, String docId, Class<T> clazz) {
		String r = getDocAsJson(index, docId);
		if (r!=null) {
			JSONObject o = JSONObject.parseObject(r);
			return o.toJavaObject(clazz);
		} 
		return null;
	}
	
	public static boolean deleteDocById(String index, String docId) {
		boolean result = false;

		RestHighLevelClient client = getClient();

		DeleteRequest deleteRequest  = new DeleteRequest(index).id(docId);
		
		try {
			DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
			
			if (deleteResponse.getShardInfo().getSuccessful() == deleteResponse.getShardInfo().getTotal()) {
				result = true;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	public static boolean upDateById(String index, String docId, Map<String, Object> map) {
		boolean result = false;

		RestHighLevelClient client = getClient();

		UpdateRequest updateRequest  = new UpdateRequest().index(index).id(docId).doc(map);
		
		try {
			UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
			
			if (updateResponse.getShardInfo().getSuccessful() == updateResponse.getShardInfo().getTotal()) {
				result = true;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	public static boolean upDateById(String index, String docId, Object entity) {
		boolean result = false;

		RestHighLevelClient client = getClient();

		UpdateRequest updateRequest  = new UpdateRequest().index(index).id(docId).doc(JsonBeanUtil.transBean2Json(entity), XContentType.JSON);
		
		try {
			UpdateResponse deleteResponse = client.update(updateRequest, RequestOptions.DEFAULT);
			
			if (deleteResponse.getShardInfo().getSuccessful() == deleteResponse.getShardInfo().getTotal()) {
				result = true;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	public static boolean upSertById(String index, String docId, Object entity) {
		boolean result = false;

		RestHighLevelClient client = getClient();

		UpdateRequest updateRequest  = new UpdateRequest().index(index).id(docId).upsert(JsonBeanUtil.transBean2Json(entity), XContentType.JSON);
		try {
			UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
			
			if (updateResponse.getShardInfo().getSuccessful() == updateResponse.getShardInfo().getTotal()) {
				result = true;
			}
		} catch (Exception e) {
			String m = e.getMessage();
			if(m.indexOf("script or doc is missing")>=0) {
				ElasticSearchUtils.addEntityDoc(index, docId, entity);
			}
		}
		
		return result;
	}
	
	public static List<Object> multiAndSearchDoc(String index , Map<String, Object> mustMap, Map<String, String> orderMap, Class<?> objectClass, int from, int size, String matchType) {
		List<Object> list = new ArrayList<Object>();

		RestHighLevelClient client = getClient();
		SearchRequest searchRequest = new SearchRequest().indices(index);
		
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder = buildResponse(searchSourceBuilder, mustMap, orderMap, matchType);
		searchSourceBuilder.from(from);
		searchSourceBuilder.size(size);
		searchSourceBuilder.explain(true);
		
		searchRequest.source(searchSourceBuilder); 


		SearchResponse myresponse = null;
		try {
			myresponse = client.search(searchRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		SearchHits hits = myresponse.getHits();
		for (int i = 0; i < hits.getHits().length; i++) {
			String json = hits.getHits()[i].getSourceAsString();
			String id = hits.getHits()[i].getId();
//			JSONObject jo = JSONObject.fromObject(json);
//			jo.put("id", id);
			com.alibaba.fastjson.JSONObject jsonObj = JSON.parseObject(json);
			jsonObj.put("id", id);

			Object bean = (Object) JsonBeanUtil.transJson2Bean(jsonObj.toJSONString(), objectClass);
			list.add(bean);
		}


		return list;
	}
	
	private static SearchSourceBuilder buildResponse(SearchSourceBuilder responsebuilder, Map<String, ?> mustMap, Map<String, String> orderMap, String matchType) {
		if (null != mustMap && mustMap.size() > 0) {
			// 创建�?个查�?
			BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

			// 这里查询的条件用map传�??
			for (String key : mustMap.keySet()) {
					
				QueryBuilder match = null;
				
				switch (matchType) {
				case MatchTypes.MATCH:
					match = QueryBuilders.matchQuery(key, mustMap.get(key));
					break;
				case MatchTypes.MATCH_PHRASE:
					match = QueryBuilders.matchPhraseQuery(key, mustMap.get(key));
					break;
				case MatchTypes.MATCH_PHRASE_PREFIX:
					match = QueryBuilders.matchPhrasePrefixQuery(key, mustMap.get(key));
					break;
				case MatchTypes.TERM:
					match = QueryBuilders.termQuery(key, mustMap.get(key));
					break;
				case MatchTypes.TERMS:
					match = QueryBuilders.termsQuery(key, mustMap.get(key).toString().split(","));
					break;
				default:
					match = QueryBuilders.matchPhraseQuery(key, mustMap.get(key));
					break;
				}
				//普通and查询,还是用matchPhrase短语匹配算了，适用性好些
				queryBuilder.must(match);
			}
			// 查询
			responsebuilder.query(queryBuilder);
		}

		if(orderMap!=null && orderMap.size()>0){
			for (String key : orderMap.keySet()) {
				String value = orderMap.get(key)==null?"":orderMap.get(key).toString();
				if("desc".equals(value)){
					responsebuilder.sort(new FieldSortBuilder(key).order(SortOrder.DESC));
				}else{
					responsebuilder.sort(new FieldSortBuilder(key).order(SortOrder.ASC));
				}
			}
		}
		
		//默认按分数排
		responsebuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); 
		
		return responsebuilder;
	}
	
	public static <T> List<T> multiOrSearchDoc(String index, String type, Map<String, Object> shouldMap, Map<String, String> orderMap, Class<T> objectClass, int from, int size, String matchType) {
		List<T> list = new ArrayList<T>();

		RestHighLevelClient client = getClient();
		SearchRequest searchRequest = new SearchRequest().indices(index);
		
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.from(from);
		searchSourceBuilder.size(size);
		searchSourceBuilder.explain(true);

		if (null != shouldMap && shouldMap.size() > 0) {
			// 创建�?个查�?
			BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

			// 这里查询的条件用map传�??
			for (String key : shouldMap.keySet()) {
				QueryBuilder match = null;
				
				switch (matchType) {
				case MatchTypes.MATCH:
					match = QueryBuilders.matchQuery(key, shouldMap.get(key));
					break;
				case MatchTypes.MATCH_PHRASE:
					match = QueryBuilders.matchPhraseQuery(key, shouldMap.get(key));
					break;
				case MatchTypes.MATCH_PHRASE_PREFIX:
					match = QueryBuilders.matchPhrasePrefixQuery(key, shouldMap.get(key));
					break;
				case MatchTypes.TERM:
					match = QueryBuilders.termQuery(key, shouldMap.get(key));
					break;
				case MatchTypes.TERMS:
					match = QueryBuilders.termsQuery(key, shouldMap.get(key).toString().split(","));
					break;
				default:
					match = QueryBuilders.matchPhraseQuery(key, shouldMap.get(key));
					break;
				}
				
				queryBuilder.should(match);// or查询
			}
			// 查询
			searchSourceBuilder.query(queryBuilder);
		}

		if(orderMap!=null && orderMap.size()>0){
			for (String key : orderMap.keySet()) {
				String value = orderMap.get(key)==null?"":orderMap.get(key).toString();
				if("desc".equals(value)){
					searchSourceBuilder.sort(new FieldSortBuilder(key).order(SortOrder.DESC));
				}else{
					searchSourceBuilder.sort(new FieldSortBuilder(key).order(SortOrder.ASC));
				}
			}
		}
		searchRequest.source(searchSourceBuilder); 
		
		SearchResponse myresponse = null;
		try {
			myresponse = client.search(searchRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		SearchHits hits = myresponse.getHits();
		for (int i = 0; i < hits.getHits().length; i++) {
			String json = hits.getHits()[i].getSourceAsString();
			String id = hits.getHits()[i].getId();
			com.alibaba.fastjson.JSONObject jsonObj = JSON.parseObject(json);
			jsonObj.put("id", id);

			T bean = JsonBeanUtil.transJson2Obj(jsonObj.toJSONString(), objectClass);
			list.add(bean);
		}

		return list;
	}
	
	public static HighlightBuilder buildHighlight(String index, String preTag, String postTag, int fragment_size, int number_of_fragments, String... fields) {
		HighlightBuilder highlightBuilder = new HighlightBuilder(); 
		if(StringUtils.isNotBlank(preTag)) {
			highlightBuilder.preTags(preTag);
//			"this_is_highlight_pre_tag"
		}
		if(StringUtils.isNotBlank(postTag)) {
			highlightBuilder.postTags(postTag);
//			"this_is_highlight_post_tag"
		}
		for(String field :fields) {
			HighlightBuilder.Field highlightTitle = new HighlightBuilder.Field(field);
			highlightTitle.fragmentSize(fragment_size);
			highlightTitle.numOfFragments(number_of_fragments);
			highlightBuilder.field(highlightTitle);
		}
		
		return highlightBuilder;
	}
	
	public static List<Map<String, Object>> multiOrSearchDocWithHighlight(String index, Map<String, Object> mustMap, Map<String, Object> shouldMap, Map<String, String> orderMap, Class<?> objectClass, String[] includes, int from, int size, String matchType) {
		
		//数据
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

		RestHighLevelClient client = getClient();
		SearchRequest searchRequest = new SearchRequest().indices(index);
		
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.from(from);
		searchSourceBuilder.size(size);
		searchSourceBuilder.explain(false);
		if(includes!=null) {
			searchSourceBuilder.fetchSource(includes, null);
		}
		
		// 创建�?个查�?
		BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
					
		List<String> fields = new ArrayList<>();
		if (null != shouldMap && shouldMap.size() > 0) {

			BoolQueryBuilder bool = QueryBuilders.boolQuery();
			
			// 这里查询的条件用map传�??
			//遍历字段
			for (String key : shouldMap.keySet()) {
				Object word = shouldMap.get(key);
				String[] ss = word.toString().split("\\s+");
				fields.add(key);
				
				QueryBuilder match = null;
				
				switch (matchType) {
					case MatchTypes.MATCH:
						match = QueryBuilders.matchQuery(key, word);
						break;
					case MatchTypes.MATCH_PHRASE:
						if(matchType.equals(MatchTypes.MATCH_PHRASE) && ss.length>1) {
							BoolQueryBuilder bool2 = QueryBuilders.boolQuery();
							for(String s : ss) {
								bool2.must(QueryBuilders.matchPhraseQuery(key, s));
							}
							match = bool2;
						}else {
							match = QueryBuilders.matchPhraseQuery(key, word);
						}
						break;
					case MatchTypes.MATCH_PHRASE_PREFIX:
						match = QueryBuilders.matchPhrasePrefixQuery(key, word);
						break;
					case MatchTypes.TERM:
						match = QueryBuilders.termQuery(key, word);
						break;
					case MatchTypes.TERMS:
						match = QueryBuilders.termsQuery(key, word.toString().split(","));
						break;
					default:
						match = QueryBuilders.matchPhraseQuery(key, shouldMap.get(key));
						break;
				}
				
				if(match!=null) {
					bool.should(match);
				}
			}
			
			queryBuilder.must(bool);
		}
		
		if (null != mustMap && mustMap.size() > 0) {

			// 这里查询的条件用map传�??
			for (String key : mustMap.keySet()) {
				fields.add(key);
				
				if(mustMap.get(key) instanceof String[]){
					String[] arrays = (String[]) mustMap.get(key);
					BoolQueryBuilder match = QueryBuilders.boolQuery();
					for(String s:arrays) {
						match.should(QueryBuilders.matchPhraseQuery(key, s));
					}
					queryBuilder.must(match);
		        }else {
		        	QueryBuilder match = QueryBuilders.matchPhraseQuery(key, mustMap.get(key));
					queryBuilder.must(match);
		        }
			}
		}

		// 查询
		searchSourceBuilder.query(queryBuilder);
					
		String[] fieldsArray = new String[fields.size()];
		searchSourceBuilder.highlighter(buildHighlight(index, null, null, -1, -1, fields.toArray(fieldsArray)));
		
		if(orderMap!=null && orderMap.size()>0){
			for (String key : orderMap.keySet()) {
				String value = orderMap.get(key)==null?"":orderMap.get(key).toString();
				if("desc".equals(value)){
					searchSourceBuilder.sort(new FieldSortBuilder(key).order(SortOrder.DESC));
				}else{
					searchSourceBuilder.sort(new FieldSortBuilder(key).order(SortOrder.ASC));
				}
			}
		}
		searchRequest.source(searchSourceBuilder); 
		
		SearchResponse myresponse = null;
		try {
			myresponse = client.search(searchRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		SearchHits hits = myresponse.getHits();
		for (int i = 0; i < hits.getHits().length; i++) {
			Map<String, Object> map = new HashMap<>();
			Map<String, String> highlight = new HashMap<>();
			
			String json = hits.getHits()[i].getSourceAsString();
//			String id = hits.getHits()[i].getId();
			com.alibaba.fastjson.JSONObject jsonObj = JSON.parseObject(json);
//			jsonObj.put("id", id);
			jsonObj.put("score", hits.getHits()[i].getScore());

			Object bean = JsonBeanUtil.transJson2Obj(jsonObj.toJSONString(), objectClass);
			map.put("bean", bean);
			
			Map<String, HighlightField> highlightJson = hits.getHits()[i].getHighlightFields();
			for(Entry<String, HighlightField> entry:highlightJson.entrySet()) {
				Text[] t = entry.getValue().getFragments();
				StringBuilder b = new StringBuilder();
				for(Text tt:t) {
					b.append(tt.toString());
				}
				highlight.put(entry.getKey(), b.toString());
			}
			map.put("highlight", highlight);
			
			map.put("allHits", hits.getTotalHits().value);
			
			
			list.add(map);
		}
		
		return list;
	}
	
public static List<Map<String, Object>> multiOrSearchDocWithHighlight(String index, List<SearchField> must, List<SearchField> should, Map<String, String> orderMap, Class<?> objectClass, String[] includes, int from, int size) {
		
		//数据
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

		RestHighLevelClient client = getClient();
		SearchRequest searchRequest = new SearchRequest().indices(index);
		
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.from(from);
		searchSourceBuilder.size(size);
		searchSourceBuilder.explain(false);
		if(includes!=null) {
			searchSourceBuilder.fetchSource(includes, null);
		}
		
		// 创建�?个查�?
		BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
					
		List<String> fields = new ArrayList<>();
		if (CollectionUtils.isNotEmpty(should)) {

			BoolQueryBuilder bool = QueryBuilders.boolQuery();
			
			// 这里查询的条件用map传�??
			//遍历字段
			for (SearchField searchField : should) {
				fields.add(searchField.getName());
				
				QueryBuilder match = buildShouldMatch(searchField);
				
				if(match!=null) {
					bool.should(match);
				}
			}
			
			queryBuilder.must(bool);
		}
		
		if (CollectionUtils.isNotEmpty(must)) {

			// 这里查询的条件用map传�??
			for (SearchField searchField:must) {
				fields.add(searchField.getName());
				queryBuilder.must(buildMustMatch(searchField));
			}
		}

		// 查询
		searchSourceBuilder.query(queryBuilder);
					
		String[] fieldsArray = new String[fields.size()];
		searchSourceBuilder.highlighter(buildHighlight(index, null, null, -1, -1, fields.toArray(fieldsArray)));
		
		if(orderMap!=null && orderMap.size()>0){
			for (String key : orderMap.keySet()) {
				String value = orderMap.get(key)==null?"":orderMap.get(key).toString();
				if("desc".equals(value)){
					searchSourceBuilder.sort(new FieldSortBuilder(key).order(SortOrder.DESC));
				}else{
					searchSourceBuilder.sort(new FieldSortBuilder(key).order(SortOrder.ASC));
				}
			}
		}
		searchRequest.source(searchSourceBuilder); 
		
		SearchResponse myresponse = null;
		try {
			myresponse = client.search(searchRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		SearchHits hits = myresponse.getHits();
		for (int i = 0; i < hits.getHits().length; i++) {
			Map<String, Object> map = new HashMap<>();
			Map<String, String> highlight = new HashMap<>();
			
			String json = hits.getHits()[i].getSourceAsString();
//			String id = hits.getHits()[i].getId();
			com.alibaba.fastjson.JSONObject jsonObj = JSON.parseObject(json);
//			jsonObj.put("id", id);
			jsonObj.put("score", hits.getHits()[i].getScore());

			Object bean = JsonBeanUtil.transJson2Obj(jsonObj.toJSONString(), objectClass);
			map.put("bean", bean);
			
			Map<String, HighlightField> highlightJson = hits.getHits()[i].getHighlightFields();
			for(Entry<String, HighlightField> entry:highlightJson.entrySet()) {
				Text[] t = entry.getValue().getFragments();
				StringBuilder b = new StringBuilder();
				for(Text tt:t) {
					b.append(tt.toString());
				}
				highlight.put(entry.getKey(), b.toString());
			}
			map.put("highlight", highlight);
			
			map.put("allHits", hits.getTotalHits().value);
			
			
			list.add(map);
		}
		
		return list;
	}
	
//	public static <T> Map<String, Object> multiOrSearchDocWithPage(String index, Map<String, Object> mustMap, Map<String, Object> shouldMap, Map<String, String> orderMap, Class<?> objectClass, int pageNum, int pageSize, String matchType) {
//		Map<String, Object> result = new HashMap<>();
//
//		//数据
//		RestHighLevelClient client = getClient();
//		SearchRequest searchRequest = new SearchRequest().indices(index);
//		
//		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//		searchSourceBuilder.from(0);
//		searchSourceBuilder.size(0);
//		searchSourceBuilder.explain(true);
//
//		// 创建�?个查�?
//		BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
//					
//		List<String> fields = new ArrayList<>();
//		if (null != shouldMap && shouldMap.size() > 0) {
//
//			// 这里查询的条件用map传�??
//			for (String key : shouldMap.keySet()) {
//				fields.add(key);
//				
//				QueryBuilder match = null;
//				
//				switch (matchType) {
//				case MatchTypes.MATCH:
//					match = QueryBuilders.matchQuery(key, shouldMap.get(key));
//					break;
//				case MatchTypes.MATCH_PHRASE:
//					match = QueryBuilders.matchPhraseQuery(key, shouldMap.get(key));
//					break;
//				case MatchTypes.MATCH_PHRASE_PREFIX:
//					match = QueryBuilders.matchPhrasePrefixQuery(key, shouldMap.get(key));
//					break;
//				case MatchTypes.TERM:
//					match = QueryBuilders.termQuery(key, shouldMap.get(key));
//					break;
//				case MatchTypes.TERMS:
//					match = QueryBuilders.termsQuery(key, shouldMap.get(key).toString().split(","));
//					break;
//				default:
//					match = QueryBuilders.matchPhraseQuery(key, shouldMap.get(key));
//					break;
//				}
//				
//				queryBuilder.should(match);// or查询
//			}
//		}
//		
//		if (null != mustMap && mustMap.size() > 0) {
//
//			// 这里查询的条件用map传�??
//			for (String key : mustMap.keySet()) {
//				fields.add(key);
//				
//				if(mustMap.get(key) instanceof String[]){
//					String[] arrays = (String[]) mustMap.get(key);
//					for(String s:arrays) {
//						QueryBuilder match = QueryBuilders.matchPhraseQuery(key, s);
//						queryBuilder.must(match);
//					}
//		        }else {
//		        	QueryBuilder match = QueryBuilders.matchPhraseQuery(key, shouldMap.get(key));
//					queryBuilder.must(match);
//		        }
//			}
//		}
//
//		// 查询
//		searchSourceBuilder.query(queryBuilder);
//
//		searchRequest.source(searchSourceBuilder); 
//		
//		SearchResponse myresponse = null;
//		try {
//			myresponse = client.search(searchRequest, RequestOptions.DEFAULT);
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		SearchHits hits = myresponse.getHits();
//
//		//总记录数
//		Long total = hits.getTotalHits().value;
//		int totalInt = total.intValue();
//		//总页数
//		int totalPage = totalInt % pageSize == 0 ? totalInt / pageSize : totalInt/ pageSize + 1;
//		//偏移量
//		int from = (pageNum-1)*pageSize;
//		String[] includes = {"cid", "title"};
////		multiOrSearchDocWithHighlight(String index, Map<String, Object> shouldMap, Map<String, String> orderMap, Class<?> objectClass, int from, int size) {
//		List<Map<String, Object>> data = multiOrSearchDocWithHighlight(index, mustMap, shouldMap, orderMap, objectClass, includes, from, pageSize, matchType);
//		result.put("totalRecords", hits.getTotalHits());
//		result.put("totalPage", totalPage);
//		result.put("pageSize", pageSize);
//		result.put("pageNum", pageNum);
//		result.put("data", data);
//
//		return result;
//	}
	
	public static Map<String, HighlightField> searchSingleDocsHighlight(String index, Map<String, Object> mustMap, Map<String, Object> shouldMap, String matchType) {
		RestHighLevelClient client = getClient();
		SearchRequest searchRequest = new SearchRequest().indices(index);
		
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.from(0);
		searchSourceBuilder.size(1);
		searchSourceBuilder.explain(false);
		List<String> fields = new ArrayList<>();
		// 创建�?个查�?
		BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
					
		if (null != shouldMap && shouldMap.size() > 0) {

			// 这里查询的条件用map传�??
			for (String key : shouldMap.keySet()) {
				fields.add(key);
				
				QueryBuilder match = null;
				
				switch (matchType) {
				case MatchTypes.MATCH:
					match = QueryBuilders.matchQuery(key, shouldMap.get(key));
					break;
				case MatchTypes.MATCH_PHRASE:
					match = QueryBuilders.matchPhraseQuery(key, shouldMap.get(key));
					break;
				case MatchTypes.MATCH_PHRASE_PREFIX:
					match = QueryBuilders.matchPhrasePrefixQuery(key, shouldMap.get(key));
					break;
				case MatchTypes.TERM:
					match = QueryBuilders.termQuery(key, shouldMap.get(key));
					break;
				case MatchTypes.TERMS:
					match = QueryBuilders.termsQuery(key, shouldMap.get(key).toString().split(","));
					break;
				default:
					match = QueryBuilders.matchQuery(key, shouldMap.get(key));
					break;
				}
				
				queryBuilder.should(match);// or查询
			}
		}
		
		if (null != mustMap && mustMap.size() > 0) {

			// 这里查询的条件用map传�??
			for (String key : mustMap.keySet()) {
				fields.add(key);
				
				QueryBuilder match = null;
				
				switch (matchType) {
				case MatchTypes.MATCH:
					match = QueryBuilders.matchQuery(key, mustMap.get(key));
					break;
				case MatchTypes.MATCH_PHRASE:
					match = QueryBuilders.matchPhraseQuery(key, mustMap.get(key));
					break;
				case MatchTypes.MATCH_PHRASE_PREFIX:
					match = QueryBuilders.matchPhrasePrefixQuery(key, mustMap.get(key));
					break;
				case MatchTypes.TERM:
					match = QueryBuilders.termQuery(key, mustMap.get(key));
					break;
				case MatchTypes.TERMS:
					match = QueryBuilders.termsQuery(key, mustMap.get(key).toString().split(","));
					break;
				default:
					match = QueryBuilders.matchQuery(key, mustMap.get(key));
					break;
				}
				
				queryBuilder.must(match);// and查询
			}
		}

		// 查询
		searchSourceBuilder.query(queryBuilder);
		String[] fieldsArray = new String[fields.size()];
		searchSourceBuilder.highlighter(buildHighlight(index, null, null, Integer.MAX_VALUE, 0, fields.toArray(fieldsArray)));
					
		searchRequest.source(searchSourceBuilder); 
		
		SearchResponse myresponse = null;
		try {
			myresponse = client.search(searchRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		SearchHits hits = myresponse.getHits();
		Map<String, HighlightField> highlightJson = hits.getHits()[0].getHighlightFields();
		
		return highlightJson;
	}
	

	/**
	 * 清空索引数据
	 */
	public static long clearIndex(String index) {
		return deleteByQuery(index, QueryBuilders.matchAllQuery());
	}
	
	public static long deleteByQuery(String index, QueryBuilder queryBuilder) {
		RestHighLevelClient client = getClient();
		//参数为索引名，可以不指定，可以一个，可以多个
		DeleteByQueryRequest request = new DeleteByQueryRequest(index);
		// 更新时版本冲突
		request.setConflicts("proceed");
		// 设置查询条件，第一个参数是字段名，第二个参数是字段的值
		request.setQuery(queryBuilder);
		// 批次大小
		request.setBatchSize(1000);
		// 并行
		request.setSlices(2);
		// 使用滚动参数来控制“搜索上下文”存活的时间
		request.setScroll(TimeValue.timeValueMinutes(10));
		// 超时
		request.setTimeout(TimeValue.timeValueMinutes(2));
		// 刷新索引
		request.setRefresh(true);
		try {
			BulkByScrollResponse response = client.deleteByQuery(request, RequestOptions.DEFAULT);
			return response.getStatus().getDeleted();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return -1;
	}
	
	public static boolean createIndex(String index, String mapping) throws IOException {
		CreateIndexRequest request = new CreateIndexRequest(index);//创建索引
        //创建的每个索引都可以有与之关联的特定设置。
        request.settings(Settings.builder()
                .put("index.number_of_shards", 3)
                .put("index.number_of_replicas", 2)
        );
        if(StringUtils.isNoneBlank(mapping)) {
        	request.mapping(mapping, XContentType.JSON);
        }
        
        //可选参数
        request.setTimeout(TimeValue.timeValueMinutes(2));//超时,等待所有节点被确认(使用TimeValue方式)
        //同步执行
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);

        //返回的CreateIndexResponse允许检索有关执行的操作的信息，如下所示：
        boolean acknowledged = createIndexResponse.isAcknowledged();//指示是否所有节点都已确认请求
        return acknowledged;
	}
	
	private static QueryBuilder buildShouldMatch(SearchField searchField) {
		Object word = searchField.getValue();
		String[] ss = word.toString().split("\\s+");
		
		QueryBuilder match = null;
		switch (searchField.getSearchType()) {
			case MatchTypes.MATCH:
				match = QueryBuilders.matchQuery(searchField.getName(), word);
				break;
			case MatchTypes.MATCH_PHRASE:
				if(MatchTypes.MATCH_PHRASE.equals(searchField.getSearchType()) && ss.length>1) {
					BoolQueryBuilder bool2 = QueryBuilders.boolQuery();
					for(String s : ss) {
						bool2.must(QueryBuilders.matchPhraseQuery(searchField.getName(), s));
					}
					match = bool2;
				}else {
					match = QueryBuilders.matchPhraseQuery(searchField.getName(), word);
				}
				break;
			case MatchTypes.MATCH_PHRASE_PREFIX:
				match = QueryBuilders.matchPhrasePrefixQuery(searchField.getName(), word);
				break;
			case MatchTypes.TERM:
				match = QueryBuilders.termQuery(searchField.getName(), word);
				break;
			case MatchTypes.TERMS:
				match = QueryBuilders.termsQuery(searchField.getName(), word.toString().split(","));
				break;
			default:
				match = QueryBuilders.matchPhraseQuery(searchField.getName(), searchField.getValue());
				break;
		}
		
		return match;
	}
	
	private static QueryBuilder buildMustMatch(SearchField searchField) {
		Object word = searchField.getValue();
		
		
		QueryBuilder match = null;
		switch (searchField.getSearchType()) {
			case MatchTypes.MATCH:
				if(searchField.getValue() instanceof String[]){
					String[] arrays = (String[]) searchField.getValue();
					BoolQueryBuilder bool = QueryBuilders.boolQuery();
					for(String s:arrays) {
						bool.should(QueryBuilders.matchPhraseQuery(searchField.getName(), s));
					}
					match = bool;
		        }else {
		        	match = QueryBuilders.matchQuery(searchField.getName(), word);
		        }
				break;
			case MatchTypes.MATCH_PHRASE:
				if(searchField.getValue() instanceof String[]){
					String[] arrays = (String[]) searchField.getValue();
					BoolQueryBuilder bool = QueryBuilders.boolQuery();
					for(String s:arrays) {
						bool.should(QueryBuilders.matchPhraseQuery(searchField.getName(), s));
					}
					match = bool;
		        }else {
		        	match = QueryBuilders.matchPhraseQuery(searchField.getName(), word);
		        }
				break;
			case MatchTypes.MATCH_PHRASE_PREFIX:
				if(searchField.getValue() instanceof String[]){
					String[] arrays = (String[]) searchField.getValue();
					BoolQueryBuilder bool = QueryBuilders.boolQuery();
					for(String s:arrays) {
						bool.should(QueryBuilders.matchPhraseQuery(searchField.getName(), s));
					}
					match = bool;
		        }else {
		        	match = QueryBuilders.matchPhrasePrefixQuery(searchField.getName(), word);
		        }
				break;
			case MatchTypes.TERM:
				if(searchField.getValue() instanceof String[]){
					String[] arrays = (String[]) searchField.getValue();
					BoolQueryBuilder bool = QueryBuilders.boolQuery();
					for(String s:arrays) {
						bool.should(QueryBuilders.matchPhraseQuery(searchField.getName(), s));
					}
					match = bool;
		        }else {
		        	match = QueryBuilders.termQuery(searchField.getName(), word);
		        }
				break;
			case MatchTypes.TERMS:
				if(searchField.getValue() instanceof String[]){
					String[] arrays = (String[]) searchField.getValue();
					BoolQueryBuilder bool = QueryBuilders.boolQuery();
					for(String s:arrays) {
						bool.should(QueryBuilders.matchPhraseQuery(searchField.getName(), s));
					}
					match = bool;
		        }else {
		        	match = QueryBuilders.termsQuery(searchField.getName(), word.toString().split(","));
		        }
		        break;
			default:
				if(searchField.getValue() instanceof String[]){
					String[] arrays = (String[]) searchField.getValue();
					BoolQueryBuilder bool = QueryBuilders.boolQuery();
					for(String s:arrays) {
						bool.should(QueryBuilders.matchPhraseQuery(searchField.getName(), s));
					}
					match = bool;
		        }else {
		        	match = QueryBuilders.matchPhraseQuery(searchField.getName(), searchField.getValue());
		        }
		        break;
		}
		
		return match;
	}
	
}